# 导入Flask相关模块，用于构建Web应用
from flask import Flask, render_template, request, jsonify, Response, session, current_app
# 导入json模块，用于处理JSON数据
import json
# 导入requests模块，用于发送HTTP请求
import requests
# 从数据库模型模块导入数据库实例和模型类
from models.database import db, Conversation, Message, Setting
# 从配置文件导入配置类
from config import Config
# 导入os模块，用于处理文件路径和系统操作
import os
# 导入datetime模块，用于处理日期和时间
from datetime import datetime
# 导入logging模块，用于记录日志
import logging

# 配置日志，设置日志级别为DEBUG
logging.basicConfig(level=logging.DEBUG)
# 创建一个日志记录器
logger = logging.getLogger(__name__)

# 定义创建Flask应用的函数
def create_app():
    # 初始化Flask应用实例
    app = Flask(__name__)
    # 从配置类加载应用配置
    app.config.from_object(Config)
    
    # 构建实例配置文件的路径
    instance_config_path = os.path.join(app.instance_path, 'config.py')
    # 若实例配置文件存在，则加载该配置
    if os.path.exists(instance_config_path):
        app.config.from_pyfile(instance_config_path)
    
    # 初始化数据库
    db.init_app(app)
    
    # 在应用上下文环境中创建数据库表
    with app.app_context():
        db.create_all()
    
    # 定义首页路由，返回聊天界面
    @app.route('/')
    def index():
        # 查询所有对话，并按更新时间降序排列
        conversations = Conversation.query.order_by(Conversation.updated_at.desc()).all()
        # 渲染聊天界面模板，并传递对话列表
        return render_template('index.html', conversations=conversations)
    
    # 定义设置页面路由，返回设置页面
    @app.route('/settings')
    def settings():
        # 渲染设置页面模板
        return render_template('settings.html')
    
    # 定义API路由，用于获取所有对话
    @app.route('/api/conversations')
    def get_conversations():
        # 查询所有对话，并按更新时间降序排列
        conversations = Conversation.query.order_by(Conversation.updated_at.desc()).all()
        # 将对话对象转换为字典并以JSON格式返回
        return jsonify([conv.to_dict() for conv in conversations])
    
    # 定义API路由，用于创建新对话
    @app.route('/api/conversations', methods=['POST'])
    def create_conversation():
        # 创建新的对话对象
        conversation = Conversation()
        # 将新对话添加到数据库会话
        db.session.add(conversation)
        # 提交数据库会话，保存新对话
        db.session.commit()
        # 将新对话对象转换为字典并以JSON格式返回
        return jsonify(conversation.to_dict())
    
    # 定义API路由，用于获取特定对话
    @app.route('/api/conversations/<int:conversation_id>')
    def get_conversation(conversation_id):
        # 查询特定ID的对话，若不存在则返回404错误
        conversation = Conversation.query.get_or_404(conversation_id)
        # 查询该对话下的所有消息，并按创建时间升序排列
        messages = Message.query.filter_by(conversation_id=conversation_id).order_by(Message.created_at.asc()).all()
        
        # 将对话和消息对象转换为字典并以JSON格式返回
        return jsonify({
            'conversation': conversation.to_dict(),
            'messages': [msg.to_dict() for msg in messages]
        })
    
    # 定义API路由，用于删除特定对话
    @app.route('/api/conversations/<int:conversation_id>', methods=['DELETE'])
    def delete_conversation(conversation_id):
        # 查询特定ID的对话，若不存在则返回404错误
        conversation = Conversation.query.get_or_404(conversation_id)
        # 从数据库会话中删除该对话
        db.session.delete(conversation)
        # 提交数据库会话，保存删除操作
        db.session.commit()
        # 返回操作成功的JSON响应
        return jsonify({'success': True})
    
    # 定义API路由，用于更新特定对话的标题
    @app.route('/api/conversations/<int:conversation_id>/title', methods=['PUT'])
    def update_conversation_title(conversation_id):
        # 查询特定ID的对话，若不存在则返回404错误
        conversation = Conversation.query.get_or_404(conversation_id)
        # 获取请求中的JSON数据
        data = request.get_json()
        # 更新对话标题，若未提供则使用默认值
        conversation.title = data.get('title', '新对话')
        # 提交数据库会话，保存更新操作
        db.session.commit()
        # 将更新后的对话对象转换为字典并以JSON格式返回
        return jsonify(conversation.to_dict())
    
    # 定义API路由，用于发送消息并获取AI回复
    @app.route('/api/conversations/<int:conversation_id>/messages', methods=['POST'])
    def send_message(conversation_id):
        # 查询特定ID的对话，若不存在则返回404错误
        conversation = Conversation.query.get_or_404(conversation_id)
        # 获取请求中的JSON数据
        data = request.get_json()
        # 获取用户发送的消息内容
        user_message = data.get('message', '')
        
        # 若消息内容为空，返回错误响应
        if not user_message:
            return jsonify({'error': '消息内容不能为空'}), 400
        
        # 保存用户消息
        user_msg = Message(
            conversation_id=conversation_id,
            role='user',
            content=user_message
        )
        # 将用户消息添加到数据库会话
        db.session.add(user_msg)
        # 立即提交数据库会话，保存用户消息
        db.session.commit()  # 立即提交用户消息
        
        # 获取该对话下的所有消息，并按创建时间升序排列
        messages = Message.query.filter_by(conversation_id=conversation_id).order_by(Message.created_at.asc()).all()
        
        # 准备调用DeepSeek API所需的API密钥
        api_key = Setting.get_value('DEEPSEEK_API_KEY') or app.config.get('DEEPSEEK_API_KEY', '')
        # 若未设置API密钥，返回错误响应
        if not api_key:
            return jsonify({'error': '未设置API密钥'}), 500
        
        # 构建调用API所需的消息历史
        message_history = []
        for msg in messages:
            message_history.append({"role": msg.role, "content": msg.content})
        
        # 调用DeepSeek API
        headers = {
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json"
        }

        payload = {
            "model": Setting.get_value('DEEPSEEK_MODEL') or app.config.get('DEEPSEEK_MODEL', 'deepseek-chat'),
            "messages": message_history,
            "temperature": float(Setting.get_value('DEEPSEEK_TEMPERATURE') or app.config.get('DEEPSEEK_TEMPERATURE', 0.7)),
            "max_tokens": int(Setting.get_value('DEEPSEEK_MAX_TOKENS') or app.config.get('DEEPSEEK_MAX_TOKENS', 2048)),
            "stream": True
        }

        try:
            # 发送POST请求调用DeepSeek API，启用流式响应
            response = requests.post(
                "https://api.deepseek.com/chat/completions",
                headers=headers,
                json=payload,
                stream=True
            )
            # 检查响应状态，若有错误则抛出异常
            response.raise_for_status()
            
            # 记录成功的API调用
            logger.info("DeepSeek API调用成功")
            
            # 定义流式响应生成器
            def generate():
                # 用于存储AI回复的内容
                assistant_content = ""
                
                # 在生成器内部创建应用上下文
                with app.app_context():
                    try:
                        # 迭代流式响应的每一行
                        for line in response.iter_lines():
                            if line:
                                # 处理流式响应数据
                                line_text = line.decode('utf-8')
                                if line_text.startswith('data: '):
                                    # 去掉"data: "前缀
                                    data_str = line_text[6:]  
                                    if data_str == '[DONE]':
                                        break
                                    try:
                                        # 解析JSON数据
                                        data = json.loads(data_str)
                                        if 'choices' in data and len(data['choices']) > 0:
                                            # 获取响应中的增量内容
                                            delta = data['choices'][0].get('delta', {})
                                            if 'content' in delta:
                                                content = delta['content']
                                                assistant_content += content
                                                # 生成流式响应数据
                                                yield f"data: {json.dumps({'content': content})}\n\n"
                                    except json.JSONDecodeError:
                                        continue
                        
                        # 保存AI回复
                        assistant_msg = Message(
                            conversation_id=conversation_id,
                            role='assistant',
                            content=assistant_content
                        )
                        # 将AI回复添加到数据库会话
                        db.session.add(assistant_msg)
                        # 更新对话的更新时间
                        conversation.updated_at = datetime.utcnow()
                        # 提交数据库会话，保存AI回复
                        db.session.commit()
                        
                    except Exception as e:
                        # 记录流式响应处理错误
                        logger.error(f"流式响应处理错误: {str(e)}")
                        # 即使出错也要返回完成信号
                        yield "data: [DONE]\n\n"
                        raise
                
                # 返回完成信号
                yield "data: [DONE]\n\n"
            
            # 返回流式响应
            return Response(generate(), mimetype='text/event-stream')
            
        except requests.exceptions.RequestException as e:
            # 记录详细的错误信息
            logger.error(f"DeepSeek API调用失败: {str(e)}")
            if hasattr(e, 'response') and e.response is not None:
                logger.error(f"响应状态码: {e.response.status_code}")
                logger.error(f"响应内容: {e.response.text}")
            
            # 返回API调用失败的错误响应
            return jsonify({'error': f'API调用失败: {str(e)}'}), 500
    
    # 定义API路由，用于获取设置信息
    @app.route('/api/settings')
    def get_settings():
        # 获取各项设置信息
        settings = {
            'DEEPSEEK_API_KEY': Setting.get_value('DEEPSEEK_API_KEY', ''),
            'DEEPSEEK_MODEL': Setting.get_value('DEEPSEEK_MODEL', 'deepseek-chat'),
            'DEEPSEEK_TEMPERATURE': Setting.get_value('DEEPSEEK_TEMPERATURE', '0.7'),
            'DEEPSEEK_MAX_TOKENS': Setting.get_value('DEEPSEEK_MAX_TOKENS', '2048')
        }
        # 将设置信息以JSON格式返回
        return jsonify(settings)
    
    # 定义API路由，用于更新设置信息
    @app.route('/api/settings', methods=['POST'])
    def update_settings():
        # 获取请求中的JSON数据
        data = request.get_json()
        
        # 遍历需要更新的设置项
        for key in ['DEEPSEEK_API_KEY', 'DEEPSEEK_MODEL', 'DEEPSEEK_TEMPERATURE', 'DEEPSEEK_MAX_TOKENS']:
            if key in data:
                # 更新设置值
                Setting.set_value(key, str(data[key]))
        
        # 返回操作成功的JSON响应
        return jsonify({'success': True})
    
    # 定义API路由，用于测试API连接
    @app.route('/api/test-connection', methods=['POST'])
    def test_api_connection():
        # 获取请求中的JSON数据
        data = request.get_json()
        # 获取API密钥
        api_key = data.get('api_key', '')
        # 获取模型名称
        model = data.get('model', 'deepseek-chat')
        
        # 若API密钥为空，返回错误响应
        if not api_key:
            return jsonify({'success': False, 'error': 'API密钥不能为空'})
        
        # 测试API连接
        headers = {
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json"
        }
        
        payload = {
            "model": model,
            "messages": [{"role": "user", "content": "Hello"}],
            "max_tokens": 5
        }
        
        try:
            # 发送POST请求测试API连接，设置超时时间为10秒
            response = requests.post(
                "https://api.deepseek.com/chat/completions",
                headers=headers,
                json=payload,
                timeout=10  # 设置超时时间
            )
            
            # 若响应状态码为200，返回连接成功的响应
            if response.status_code == 200:
                return jsonify({'success': True})
            else:
                # 处理API返回的错误信息
                error_msg = f"API返回错误: {response.status_code}"
                try:
                    error_data = response.json()
                    if 'error' in error_data and 'message' in error_data['error']:
                        error_msg = error_data['error']['message']
                except:
                    pass
                # 返回连接失败的响应
                return jsonify({'success': False, 'error': error_msg})
                
        except requests.exceptions.RequestException as e:
            # 返回网络连接错误的响应
            return jsonify({'success': False, 'error': f'网络连接错误: {str(e)}'})
    
    # 返回Flask应用实例
    return app

# 若作为主程序运行
if __name__ == '__main__':
    # 创建Flask应用实例
    app = create_app()
    # 启动Flask应用，开启调试模式
    app.run(debug=True)